﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Drawing;
using Win32SDK;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace GameEditor.Common
{
    public class FileSystemNode
    {
        /// <summary>
        /// 节点名字
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// 节点图标
        /// </summary>
        public Icon Image { get; set; }

        /// <summary>
        /// 节点图标
        /// </summary>
        public Icon SelectedImage { get; set; }

        /// <summary>
        /// 节点对应的磁盘上的绝对路径
        /// </summary>
        public string Path { get; set; }
        /// <summary>
        /// 节点对应的相对于根路径的相对路径
        /// </summary>
        public string RelativePath { get; set; }

        public bool IsDirectory { get; set; }

        /// <summary>
        /// 根结点定义
        /// </summary>
        public static readonly FileSystemNode Root = null;
    }

    public interface IOpenResourceDialog
    {
        void CreateNode(FileSystemNode parentNode, FileSystemNode childNode);
        FileSystemNode SelectedNode { get; set; }
        void OnOK();
    }

    /// <summary>
    /// 实现该接口给资源对话框提供相关文件系统资源
    /// </summary>
    public interface IFileSystemProvider
    {
        /// <summary>
        /// 获取指定节点下的子节点
        /// </summary>
        /// <returns></returns>
        FileSystemNode[] GetNodes(FileSystemNode parentNode);
    }

    public abstract class ResourceProvider: IDisposable
    {
        /// <summary>
        /// 对话框标题
        /// </summary>
        public virtual string DialogTitle
        {
            get
            {
                return "打开资源";
            }
        }
        /// <summary>
        /// 文件面板标题
        /// </summary>
        public virtual string FilePanelTitle
        {
            get
            {
                return "选择文件：";
            }
        }
        /// <summary>
        /// 内容面板标题
        /// </summary>
        public virtual string ContentPanelTitle
        {
            get
            {
                return "选择资源：";
            }
        }


        IFileSystemProvider provider = null;
        Control contentView = null;
        ContextMenuStrip contextMenuStrip = null;
        protected IOpenResourceDialog resourceDialog = null;

        /// <summary>
        /// 文件系统提供者
        /// </summary>
        public IFileSystemProvider FileSystemProvider
        {
            get { return provider; }
        }
        /// <summary>
        /// 文件内容视图
        /// </summary>
        public Control ContentView
        {
            get { return contentView; }
        }
        /// <summary>
        /// 文件视图的上下文菜单
        /// </summary>
        public ContextMenuStrip ContextMenu
        {
            get { return contextMenuStrip; }
        }

        public ResourceProvider()
        {
            provider = CreateFileSystemProvider();
            contentView = CreateContentView();
            contextMenuStrip = CreateFSContextMenu();
        }


        public virtual void Dispose()
        {
            if (provider is IDisposable)
                (provider as IDisposable).Dispose();
            if (contentView != null)
                contentView.Dispose();
            if (contextMenuStrip != null)
                contextMenuStrip.Dispose();
        }


        protected virtual ContextMenuStrip CreateFSContextMenu()
        {
            return null;
        }

        protected virtual IFileSystemProvider CreateFileSystemProvider()
        {
            return new StandardFileSystemProvider { RootPath = @"E:\work\work\trunk\client_output\GameData" };
        }
        /// <summary>
        /// 创建内容视图
        /// </summary>
        /// <returns></returns>
        protected abstract Control CreateContentView();
        /// <summary>
        /// 用户点击了节点对象，更新内容视图
        /// </summary>
        /// <param name="contentView"></param>
        /// <param name="node"></param>
        public abstract void UpdateContentView(FileSystemNode node);

        /// <summary>
        /// 由当前视图以及当前文件系统节点来创建结果对象
        /// </summary>
        /// <param name="contentView"></param>
        /// <param name="node"></param>
        /// <returns></returns>
        public virtual void CreateResult(FileSystemNode selectedNode)
        {
        }


        /// <summary>
        /// 做验证，确定是否允许结束选择过程
        /// </summary>
        /// <returns></returns>
        public virtual bool Validate()
        {
            return true;
        }

        internal void Bind(IOpenResourceDialog openResourceDialog)
        {
            resourceDialog = openResourceDialog;
        }
    }
    /// <summary>
    /// 标准的文件系统提供器，可覆盖此类以便实现复杂筛选
    /// </summary>
    public class StandardFileSystemProvider : IFileSystemProvider
    {

        protected static Icon FileIcon = null;
        protected static Icon DirectoryIcon = null;
        protected static Icon OpenedDirectoryIcon = null;


        public string RootPath { get; set; }


        protected virtual bool FilterDirectory(string path)
        {
            return (File.GetAttributes(path) & (FileAttributes.Hidden | FileAttributes.System)) == 0;
        }
        protected virtual bool FilterFile(string path)
        {
            return (File.GetAttributes(path) & (FileAttributes.Hidden | FileAttributes.System)) == 0;
        }

        static StandardFileSystemProvider()
        {
            SHFILEINFO fileInfo;

            string SysPath = Environment.GetFolderPath(Environment.SpecialFolder.System);
            IntPtr imageList = Shell32.SHGetFileInfo(SysPath, 0, out fileInfo, (uint)Marshal.SizeOf(typeof(SHFILEINFO)), SHGFI.SysIconIndex | SHGFI.SmallIcon);

            int imageIndex = Shell32.GetFileImageIndex(SysPath, false, false, false);
            int openedImageIndex = Shell32.GetFileImageIndex(SysPath, false, true, false);

            string FilePath = Path.Combine(SysPath, "drivers\\acpi.sys");
            int fileIndex = Shell32.GetFileImageIndex(FilePath, false, false, false);

            DirectoryIcon = Icon.FromHandle(ComCtl32.ImageList_GetIcon(imageList, imageIndex, ILD.Normal));
            OpenedDirectoryIcon = Icon.FromHandle(ComCtl32.ImageList_GetIcon(imageList, openedImageIndex, ILD.Normal));
            FileIcon = Icon.FromHandle(ComCtl32.ImageList_GetIcon(imageList, fileIndex, ILD.Normal));


        }

        protected virtual FileSystemNode CreateFileNode(string fileName)
        {
            return new FileSystemNode
            {
                Name = Path.GetFileName(fileName),
                Path = fileName,
                Image = FileIcon,
                SelectedImage = FileIcon,
                IsDirectory = false
            };
        }
        protected virtual FileSystemNode CreateDirectoryNode(string path)
        {
            return new FileSystemNode
            {
                Name = Path.GetFileName(path),
                Path = path,
                Image = DirectoryIcon,
                SelectedImage = OpenedDirectoryIcon,
                IsDirectory = true
            };
        }

        /// <summary>
        /// 获取指定节点下的子节点
        /// </summary>
        /// <returns></returns>
        public FileSystemNode[] GetNodes(FileSystemNode parentNode)
        {
            string path = RootPath;
            string relativePath = "/";
            if (parentNode != FileSystemNode.Root)
            {
                path = Path.Combine(path, parentNode.Path);
                relativePath = parentNode.RelativePath;
            }

            List<FileSystemNode> nodes = new List<FileSystemNode>();
            foreach (string directory in Directory.GetDirectories(path))
            {
                if (!FilterDirectory(directory))
                    continue;
                FileSystemNode node = CreateDirectoryNode(directory);
                node.RelativePath = relativePath + Path.GetFileName(directory) + "/";
                nodes.Add(node);
            }
            foreach (string file in Directory.GetFiles(path))
            {
                if (!FilterFile(file))
                    continue;
                FileSystemNode node = CreateFileNode(file);
                node.RelativePath = relativePath + Path.GetFileName(file);
                nodes.Add(node);
            }
            return nodes.ToArray();
        }
    }

}
